
#include "member_BHBoxLayout.h"

using namespace BWE;

member_BHBoxLayout::member_BHBoxLayout(BHBoxLayout* layout)
{
	boss = layout;
	spacing = 0;
	pressed = false;
	handleIndex = -1;
	totalBaseWidth = 0;
}
member_BHBoxLayout::~member_BHBoxLayout()
{

}

BRect member_BHBoxLayout::handleRect(int index)
{
	int spacing = boss->spacing();
	LayoutItem& item = items(index);
	return BRect(item.rect.right(), item.rect.top(), spacing, item.rect.height());
}
void member_BHBoxLayout::checkHandle(int& handle)
{
	if (handle < 0)
		return;

	leftLimit.reset();
	for (int i = handle; i >= 0; i--)
	{
		LayoutItem& item = items[i];
		leftLimit.max() += item.maxSize.width() - item.realSize.width();
		leftLimit.min() -= item.realSize.width() - item.minSize.width();
	}

	rightLimit.reset();
	for (int i = handle + 1; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		rightLimit.max() += item.maxSize.width() - item.realSize.width();
		rightLimit.min() -= item.realSize.width() - item.minSize.width();
	}

	if (leftLimit.empty() || rightLimit.empty())
	{
		handle = -1;
	}
}
bool member_BHBoxLayout::dragHandle(const BPoint& pos)
{
	if (handleIndex < 0)
		return false;
	BPoint change = pos - pressCenter;
	leftLimit.limit(change.x());
	rightLimit.limit(change.x());
	if (change.x() == 0)
		return false;
	int leftRemain = change.x();
	for (int i = handleIndex; i >= 0; i--)
	{
		LayoutItem& item = items[i];
		CacheSize& cache = dragCaches[i];
		cache.realSize = cache.metaSize;
		int minWidth = item.minSize.width();
		if (cache.realSize.width() + leftRemain < minWidth)
		{
			leftRemain -= minWidth - cache.realSize.width();
			cache.realSize.width() = minWidth;
			continue;
		}
		int maxWidth = item.maxSize.width();
		if (cache.realSize.width() + leftRemain > maxWidth)
		{
			leftRemain -= maxWidth - cache.realSize.width();
			cache.realSize.width() = maxWidth;
			continue;
		}
		cache.realSize.width() += leftRemain;
		leftRemain = 0;
		break;
	}
	int rightRemain = -change.x();
	for (int i = handleIndex + 1; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		CacheSize& cache = dragCaches[i];
		cache.realSize = cache.metaSize;
		int minWidth = item.minSize.width();
		if (cache.realSize.width() + rightRemain < minWidth)
		{
			rightRemain -= minWidth - cache.realSize.width();
			cache.realSize.width() = minWidth;
			continue;
		}
		int maxWidth = item.maxSize.width();
		if (cache.realSize.width() + rightRemain > maxWidth)
		{
			rightRemain -= maxWidth - cache.realSize.width();
			cache.realSize.width() = maxWidth;
			continue;
		}
		cache.realSize.width() += rightRemain;
		rightRemain = 0;
		break;
	}

	if (leftRemain != rightRemain)
		return false;

	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		CacheSize& cache = dragCaches[i];
		item.realSize = cache.realSize;
	}

	applyRects();

	if (totalStretch < 1.0f)
		totalStretch = 1.0f;
	int totalWidth = boss->rect().width() - totalBaseWidth;
	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		item.stretch.widthStretch() = 0.0f;
		if (totalWidth && item.realSize.width() > item.baseSize.width())
			item.stretch.widthStretch() = (float)(item.realSize.width() - item.baseSize.width()) / totalWidth * totalStretch;
	}
	return true;
}

void member_BHBoxLayout::distributeWidth()
{
	const BRect& rect = boss->rect();
	const BMargin& margin = boss->margin();
	int height = rect.height() - margin.height();

	const BSize& minSize = boss->minSize();
	const BSize& maxSize = boss->maxSize();

	totalStretch = 0.0f;
	int totalWidth = margin.width();
	int validCount = 0;
	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		if (item.prepare(0, 0, height))
			validCount++;
		totalWidth += item.realSize.width() + spacing;
		totalStretch += item.stretch.widthStretch();
	}
	if (validCount == 0)
		return;
	totalWidth -= spacing;
	totalBaseWidth = bLimit(totalWidth, minSize.width(), maxSize.width());
	if (totalBaseWidth != totalWidth)
	{
		int remainWidth = totalBaseWidth - totalWidth;
		float totalStretch = 0;
		for (int i = 0; i < items.size(); i++)
		{
			if (!items[i].finishWidth)
				totalStretch += items[i].stretch.widthStretch();
		}
		for (int i = 0; i < items.size(); i++)
		{
			if (!items[i].finishWidth)
				items[i].realSize.width() += (int)(remainWidth * items[i].stretch.widthStretch() / totalStretch);
		}
	}

	int remainWidth = boss->rect().width() - totalBaseWidth;

	while (remainWidth != 0)
	{
		float totalStretch = 0;
		for (int i = 0; i < items.size(); i++)
		{
			LayoutItem& item = items[i];
			if (item.finishWidth)
				continue;
			if (item.stretch.widthStretch() == 0.0f)
				continue;
			if (remainWidth > 0 && !(item.sizePolicy.widthPolicy() & Policy_Expanding))
			{
				item.finishWidth = true;
				continue;
			}
			if (remainWidth < 0 && !(item.sizePolicy.widthPolicy() & Policy_Shrinking))
			{
				item.finishWidth = true;
				continue;
			}
			totalStretch += item.stretch.widthStretch();
		}
		if (totalStretch < 0.00001)
			break;

		int used = 0;
		for (int i = 0; i < items.size(); i++)
		{
			LayoutItem& item = items[i];
			if (item.finishWidth)
				continue;
			int width = (int)(item.stretch.widthStretch() / totalStretch * remainWidth);
			if (width == 0)
				continue;
			int maxWidth = item.maxSize.width();
			if (width + item.realSize.width() > maxWidth)
			{
				used += maxWidth - item.realSize.width();
				item.realSize.width() = maxWidth;
				item.finishWidth = true;
				continue;
			}
			int minWidth = item.minSize.width();
			if (width + item.realSize.width() < minWidth)
			{
				used += minWidth - item.realSize.width();
				item.realSize.width() = minWidth;
				item.finishWidth = true;
				continue;
			}
			item.realSize.width() += width;
			used += width;
		}
		if (used == 0)
			break;
		remainWidth -= used;
	}
	while (remainWidth > 0)
	{
		int used = 0;
		for (int i = 0; i < items.size(); i++)
		{
			LayoutItem& item = items[i];
			if (item.ignored)
				continue;
			int expanding = item.sizePolicy.widthPolicy() & Policy_Expanding;
			if (!expanding)
				continue;
			item.realSize.width() += 1;
			remainWidth--;
			used++;
			if (remainWidth < 1)
				break;
		}
		if (used == 0)
			break;
	}
}
void member_BHBoxLayout::applyRects()
{
	const BRect& rect = boss->rect();
	const BMargin& margin = boss->margin();
	int spacing = boss->spacing();
	int height = rect.height() - margin.height();

	int posX = rect.x() + margin.left();
	int posY = rect.y() + margin.top();
	for (int i = 0; i < items.size(); i++)
	{
		LayoutItem& item = items[i];
		int width = item.realSize.width();
		item.adjust(posX, posY, width, height);
		posX += spacing + width;
	}
}
